package com.atguigu.gulimall.product.util;

import com.atguigu.common.annotation.ExcelField;
import com.atguigu.common.utils.Reflections;
import com.baomidou.mybatisplus.annotation.TableField;
import jodd.util.StringUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URLEncoder;

import java.text.SimpleDateFormat;
import java.util.*;

public class ExportExcelUtil<E> {
    private static final Logger log = LoggerFactory.getLogger(ExportExcelUtil.class);
    public ExportExcelUtil() { }

    public static String getExportField(Class<?> clsef) {
        String query = null;
        Field[] fields = clsef.getDeclaredFields();
        List<Object[]> annotationList = new ArrayList<>();
        for (Field field : fields) {
            ExcelField ef = (ExcelField)field.getAnnotation(ExcelField.class);
            if(ef!=null) {
                TableField tf = (TableField)field.getAnnotation(TableField.class);
                String value = tf.value();
                if (StringUtil.isEmpty(value)) {
                    continue;
                }
                if (query==null){
                    query = value + " AS " + field.getName();
                } else {
                    query = query + "," + value + " AS " + field.getName();
                }
            }
        }
        return query;
    }

    public void exportExcel(SXSSFWorkbook workbook, int sheetNum, String sheetTitle, Class<?> cls, List<E> dataList) {
        Field[] fields = cls.getDeclaredFields();
        List<Object[]> annotationList = new ArrayList<>();
        for(int index = 0; index < fields.length; ++index) {
            Field currentField = fields[index];
            ExcelField ef = (ExcelField)currentField.getAnnotation(ExcelField.class);
            if(ef!=null) {
                annotationList.add(new Object[]{ef, currentField});
            }
        }
        //根据注解中sort排序
        annotationList.sort(Comparator.comparing((item) -> {
            return ((ExcelField) item[0]).sort();
        }));
        // 生成一个表格
        Sheet sheet = workbook.createSheet();
        //设置列宽
        workbook.setSheetName(sheetNum, sheetTitle);
        //获取配置样式
        Map<String, CellStyle> styles = this.createStyles(workbook);
        //====================================导出标题================================
        Row rowTitle = sheet.createRow(0);//锁定行坐标
        rowTitle.setHeightInPoints(30.0F);//行高
        Cell titleCell = rowTitle.createCell(0);
        titleCell.setCellStyle((CellStyle)styles.get("title"));
        titleCell.setCellValue(sheetTitle);
        sheet.addMergedRegion(new CellRangeAddress(rowTitle.getRowNum(), rowTitle.getRowNum(), 0, annotationList.size()-1));
        Cell celltitlelast = rowTitle.createCell(annotationList.size()-1);
        celltitlelast.setCellStyle((CellStyle)styles.get("border"));
        //====================================导出列名================================
        Row row01 = sheet.createRow(1);//锁定行坐标
        row01.setHeightInPoints(20.0F);//行高
        for (Object[] item : annotationList){
            sheet.setColumnWidth(((ExcelField)item[0]).sort(),252*10+323);
            Cell cell = row01.createCell(((ExcelField)item[0]).sort()-1);
            cell.setCellStyle((CellStyle)styles.get("columnTitle"));//单元格样式
            cell.setCellValue(((ExcelField)item[0]).title());//单元格value
        }
        if (CollectionUtils.isEmpty(dataList)){
            return;
        }
        //===================================导出数据=================================
        Iterator iterator = dataList.iterator();
        Integer rowNum = 2;
        while(iterator.hasNext()) {
            Object e = iterator.next();
            Row row = sheet.createRow(rowNum++);
            Integer colunm = 0;
            Iterator var7 = annotationList.iterator();
            while(var7.hasNext()) {
                Object[] os = (Object[])var7.next();
                ExcelField ef = (ExcelField)os[0];
                Object val = null;

                try {
                    if (StringUtils.isNotBlank(ef.value())) {
                        val = Reflections.invokeGetter(e, ef.value());
                    } else if (os[1] instanceof Field) {
                        val = Reflections.invokeGetter(e, ((Field)os[1]).getName());
                    } else if (os[1] instanceof Method) {
                        val = Reflections.invokeMethod(e, ((Method)os[1]).getName(), new Class[0], new Object[0]);
                    }
                } catch (Exception var15) {
                    log.info(var15.toString());
                    val = "";
                }

                Cell cell = row.createCell(colunm);

                CellStyle style = (CellStyle)styles.get("data_column_" + colunm);
                if (style == null) {
                    style = workbook.createCellStyle();
                    style.cloneStyleFrom((CellStyle)styles.get("data" + (ef.align() >= 1 && ef.align() <= 3 ? ef.align() : "")));
                    String cellFormatString = "@";
                    style.setDataFormat(workbook.createDataFormat().getFormat(cellFormatString));
                    styles.put("data_column_" + colunm, style);
                }
                cell.setCellStyle(style);

                try {
                    if (val == null) {
                        cell.setCellValue("");
                    } else if (ef.fieldType() != Class.class) {
                        cell.setCellValue((String)ef.fieldType().getMethod("setValue", Object.class).invoke((Object)null, val));
                    } else if (val instanceof String) {
                        cell.setCellValue((String)val);
                    } else if (val instanceof Integer) {
                        cell.setCellValue((double)(Integer)val);
                    } else if (val instanceof Long) {
                        cell.setCellValue((double)(Long)val);
                    } else if (val instanceof Double) {
                        cell.setCellValue((Double)val);
                    } else if (val instanceof Float) {
                        cell.setCellValue((double)(Float)val);
                    } else if (val instanceof Date) {
                        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                        cell.setCellValue(sdf.format(val));
                    } else {
                        cell.setCellValue((String)Class.forName(this.getClass().getName().replaceAll(this.getClass().getSimpleName(), "fieldtype." + val.getClass().getSimpleName() + "Type")).getMethod("setValue", Object.class).invoke((Object)null, val));
                    }

                } catch (Exception var16) {
                    log.info("Set cell value [" + row.getRowNum() + "," + colunm + "] error: " + var16.toString());
                    if (null != val) {
                        cell.setCellValue(val.toString());
                    }
                }
                colunm++;
            }

        }
    }

    /**
     * 导出的Excel内容样式
     * @param wb
     * @return
     */
    private Map<String, CellStyle> createStyles(Workbook wb) {
        Map<String, CellStyle> styles = new HashMap();
        //======================================================================
        String fontName = "Arial";
        CellStyle style = wb.createCellStyle();
        style.setAlignment(HorizontalAlignment.CENTER);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        Font titleFont = wb.createFont();
        titleFont.setFontName(fontName);
        titleFont.setFontHeightInPoints((short)16);
        titleFont.setBold(titleFont.getBold());
        style.setFont(titleFont);
        styles.put("title", style);
        style = wb.createCellStyle();
        style.setBorderRight(BorderStyle.THIN);
        style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
        style.setBorderLeft(BorderStyle.THIN);
        style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
        style.setBorderTop(BorderStyle.THIN);
        style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
        style.setBorderBottom(BorderStyle.THIN);
        style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
        style.setWrapText(true);
        styles.put("border", style);
        style = wb.createCellStyle();
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        style.setBorderRight(BorderStyle.THIN);
        style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
        style.setBorderLeft(BorderStyle.THIN);
        style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
        style.setBorderTop(BorderStyle.THIN);
        style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
        style.setBorderBottom(BorderStyle.THIN);
        style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
        Font dataFont = wb.createFont();
        dataFont.setFontName(fontName);
        dataFont.setFontHeightInPoints((short)10);
        style.setFont(dataFont);
        styles.put("data", style);
        style = wb.createCellStyle();
        style.cloneStyleFrom((CellStyle)styles.get("data"));
        style.setAlignment(HorizontalAlignment.LEFT);
        styles.put("data1", style);
        style = wb.createCellStyle();
        style.cloneStyleFrom((CellStyle)styles.get("data"));
        style.setAlignment(HorizontalAlignment.CENTER);
        styles.put("data2", style);
        style = wb.createCellStyle();
        style.cloneStyleFrom((CellStyle)styles.get("data"));
        style.setAlignment(HorizontalAlignment.RIGHT);
        styles.put("data3", style);
        style = wb.createCellStyle();
        style.cloneStyleFrom((CellStyle)styles.get("data"));
        style.setAlignment(HorizontalAlignment.CENTER);
        style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex());
        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        Font headerFont = wb.createFont();
        headerFont.setFontName(fontName);
        headerFont.setFontHeightInPoints((short)10);
        headerFont.setBold(headerFont.getBold());
        headerFont.setColor(IndexedColors.WHITE.getIndex());
        style.setFont(headerFont);
        styles.put("header", style);
        style = wb.createCellStyle();
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        DataFormat format = wb.createDataFormat();
        style.setDataFormat(format.getFormat("@"));
        styles.put("column-style-text", style);

        style = wb.createCellStyle();
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        style.setBorderRight(BorderStyle.THIN);
        style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
        style.setBorderLeft(BorderStyle.THIN);
        style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
        style.setBorderTop(BorderStyle.THIN);
        style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
        style.setBorderBottom(BorderStyle.THIN);
        style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
        style.setAlignment(HorizontalAlignment.CENTER);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        style.setWrapText(true);
        styles.put("columnTitle", style);
        //===========================================================================
        style = wb.createCellStyle();
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        style.setBorderRight(BorderStyle.THIN);
        style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
        style.setBorderLeft(BorderStyle.THIN);
        style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
        style.setBorderTop(BorderStyle.THIN);
        style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
        style.setBorderBottom(BorderStyle.THIN);
        style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
        style.setAlignment(HorizontalAlignment.CENTER);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        style.setWrapText(true);
        styles.put("data01", style);
        return styles;
    }

    /**
     * 输出到客户端
     *
     * @param fileName 输出文件名
     */
    public ExportExcelUtil write(SXSSFWorkbook wb,HttpServletResponse response, String fileName) throws IOException {
        response.reset();
        response.setContentType("application/octet-stream; charset=utf-8");
        response.setHeader("Content-Disposition", "attachment; filename=" + ExportExcelUtil.urlEncode(fileName));
        this.write(wb,response.getOutputStream());
        return this;
    }

    /**
     * URL 编码, Encode默认为UTF-8.
     */
    public static String urlEncode(String part) {
        try {
            return URLEncoder.encode(part, "UTF-8");
        } catch (UnsupportedEncodingException var2) {
            throw new RuntimeException(var2);
        }
    }

    /**
     * 输出到文件
     *
     * @param
     */
    public ExportExcelUtil writeFile(SXSSFWorkbook wb,String name) throws FileNotFoundException, IOException {
        FileOutputStream os = new FileOutputStream(name);
        this.write(wb,os);
        return this;
    }

    /**
     * 输出数据流
     *
     * @param os 输出数据流
     */
    public ExportExcelUtil write(SXSSFWorkbook wb,OutputStream os) throws IOException {
        wb.write(os);
        return this;
    }

    /**
     * 清理临时文件
     */
    public ExportExcelUtil dispose(SXSSFWorkbook wb) {
        wb.dispose();
        return this;
    }

}
